import React, { useRef, useEffect, useState, useCallback } from "react";
import style from "./scrolToTab.module.scss";

let imgInitializedClientHeight = null;
let imgInitializedClientWidth = null;
let imgInitializedLeftOrRight = null;
let barInitializedLeft = null;
let isBarNowLeftOrLeft = "left";
const imgInitializedOpacity = 0;
const barInitializedWidth = 38;
const transitionTime = 0.6;

const ScrollToTab = ({ tabList = [], componentList = [], startIndex = 1 }) => {
  const [isNowIndex, setIsNowIndex] = useState(startIndex);
  const [historyIndex, setHistoryIndex] = useState([startIndex]);
  const scrollToTabContainer = useRef();
  const tabListAndBarContainerRef = useRef();
  const componentListRef = useRef();
  const leftImgRef = useRef();
  const rightImgRef = useRef();
  const [isScroll, setIsScroll] = useState(false);

  // 父组件滚动事件，根据具子组件的getBoundingClientRect().top值来设置子组件是否可以滚动
  const scrollFunc = useCallback(() => {
    if (
      scrollToTabContainer.current &&
      scrollToTabContainer.current.getBoundingClientRect().top > 1 // 滚动有距离偏差
    )
      isScroll && setIsScroll(false);
    else !isScroll && setIsScroll(true);
  }, [isScroll]);

  //当父组件有滚动条时，给父组件加上滚动事件
  const setScrollFuncToScrollToTabContainerParent = useCallback(() => {
    if (
      scrollToTabContainer.current.parentElement.scrollHeight >
      scrollToTabContainer.current.parentElement.offsetHeight
    ) {
      scrollToTabContainer.current.parentElement.onscroll = scrollFunc;
      // document.onmousewheel = scrollFunc;
    } else setIsScroll(true);
  }, [scrollFunc]);

  // 清除事件函数
  const clearFunc = () => {
    document.onmousemove = null;
    document.onmouseup = null;
  };

  // isNowIndex变化时,将正确的组件移动到页面中
  const setComponentInView = useCallback(() => {
    const componentListRefClientWidth = componentListRef.current.clientWidth;
    componentListRef.current.style.transition = `all ${transitionTime}s`;
    componentListRef.current.style.left =
      -1 * isNowIndex * componentListRefClientWidth + "px";
  }, [isNowIndex]);

  // isNowIndex变化时,将组件列表左右的提示图片设置到正确的位置
  const setLeftAndRightImgInView = useCallback(() => {
    const componentListRefClientWidth = componentListRef.current.clientWidth;
    leftImgRef.current.style.left =
      imgInitializedLeftOrRight +
      isNowIndex * componentListRefClientWidth +
      "px";
    rightImgRef.current.style.right =
      imgInitializedLeftOrRight -
      isNowIndex * componentListRefClientWidth +
      "px";
  }, [isNowIndex]);

  const getBarLeftOrLeftPosition = (isNowIndex, isRightOrLeft = "left") => {
    const leftOffset = Array.prototype.slice
      .call(tabListAndBarContainerRef.current.childNodes, 1)
      .reduce((total, item, index) => {
        if (index === isNowIndex) return total + item.clientWidth / 2;
        else if (index < isNowIndex) return total + item.clientWidth;
        else return total;
      }, -barInitializedWidth / 2);
    if (isRightOrLeft === "left") return leftOffset + "px";
    else if (isRightOrLeft === "right")
      return (
        tabListAndBarContainerRef.current.clientWidth -
        leftOffset -
        barInitializedWidth +
        "px"
      );
  };

  // 设置组件滑动事件
  const setEventToComponentListRef = useCallback(() => {
    const resetBarStyle = () => {
      tabListAndBarContainerRef.current.childNodes[0].style.transition = `all ${transitionTime}s`;
      tabListAndBarContainerRef.current.childNodes[0].style.width =
        barInitializedWidth + "px";
    };
    // 组件滚动时，设置左右img的宽高
    const setImgPosition = (ref, offestNum) => {
      ref.current.style.opacity =
        ref.current.style.opacity < 0.5
          ? imgInitializedOpacity + (0.5 / 200) * offestNum
          : 0.5;
      // ref.current.style.height = imgInitializedClientHeight * 0.8 + "px";
      // ref.current.style.width = imgInitializedClientWidth * 1.2 + "px";
      ref.current.style.height =
        ref.current.style.height.slice(0, -2) > imgInitializedClientHeight * 0.8
          ? imgInitializedClientHeight -
            (0.2 * imgInitializedClientHeight * offestNum) / 100 +
            "px"
          : imgInitializedClientHeight * 0.8 + "px";
      ref.current.style.width =
        ref.current.style.width.slice(0, -2) < imgInitializedClientWidth * 1.2
          ? imgInitializedClientWidth +
            (0.2 * imgInitializedClientWidth * offestNum) / 100 +
            "px"
          : imgInitializedClientWidth * 1.2 + "px";
    };
    // 重置左右Img样式
    const resetImgStyle = (ref) => {
      ref.current.style.transition = `all .8s`;
      ref.current.style.width = imgInitializedClientWidth + "px";
      ref.current.style.height = imgInitializedClientHeight + "px";
      ref.current.style.opacity = 0;
    };
    // 组件移动时，设置bar的width和left或者right(视边界情况定)
    const setJustNowBarWidthAndLeft = (offestNum) => {
      // 当前Tab的width 加上 下一个即将滚入的Tab的width 为总共可以滚动的距离
      const getJustNowEnterTabWidth = (offestNum) => {
        let nextTabWidth;
        const nowTabWidth =
          tabListAndBarContainerRef.current.childNodes[isNowIndex + 1]
            .clientWidth;
        if (offestNum > 0 && isNowIndex !== 0) {
          nextTabWidth =
            tabListAndBarContainerRef.current.childNodes[isNowIndex]
              .clientWidth;
        } else if (offestNum < 0 && isNowIndex !== componentList.length - 1) {
          nextTabWidth =
            tabListAndBarContainerRef.current.childNodes[isNowIndex + 2]
              .clientWidth;
        }
        return nowTabWidth + nextTabWidth;
      };
      // 组件滑动时，设置bar左右滑动的动效
      const setBarWidthAndLeftOrRight = (position = "left") => {
        const componentListRefClientWidth =
          componentListRef.current.clientWidth;
        const BarRef = tabListAndBarContainerRef.current.childNodes[0];
        let anotherPosition = "right";
        let positionOffset = getBarLeftOrLeftPosition(isNowIndex);
        let positionOffsetTwo = getBarLeftOrLeftPosition(
          isNowIndex + 1,
          "right"
        );

        if (position === "right") {
          anotherPosition = "left";
          positionOffset = getBarLeftOrLeftPosition(isNowIndex, "right");
          positionOffsetTwo = getBarLeftOrLeftPosition(isNowIndex - 1);
        }
        if (Math.abs(offestNum) < componentListRefClientWidth / 2) {
          isBarNowLeftOrLeft = position;
          BarRef.style[anotherPosition] = null;
          BarRef.style[position] = positionOffset;
          BarRef.style.width =
            barInitializedWidth +
            (getJustNowEnterTabWidth(offestNum) / componentListRefClientWidth) *
              Math.abs(offestNum) +
            "px";
        } else if (Math.abs(offestNum) > componentListRefClientWidth / 2) {
          isBarNowLeftOrLeft = anotherPosition;
          BarRef.style[position] = null;
          BarRef.style[isBarNowLeftOrLeft] = positionOffsetTwo;
          BarRef.style.width =
            barInitializedWidth +
            getJustNowEnterTabWidth(offestNum) / 2 -
            (getJustNowEnterTabWidth(offestNum) / componentListRefClientWidth) *
              (Math.abs(offestNum) - componentListRefClientWidth / 2) +
            "px";
        }
      };

      setBarWidthAndLeftOrRight(offestNum < 0 ? "left" : "right");
    };
    const clearTransition = () => {
      componentListRef.current.style.transition = "none";
      leftImgRef.current.style.transition = "none";
      rightImgRef.current.style.transition = "none";
      tabListAndBarContainerRef.current.childNodes[0].style.transition = "none";
    };
    // 组件点击事件
    componentListRef.current.onmousedown = function (e) {
      clearTransition();

      const [startPositionX, startTime] = [e.clientX, new Date().getTime()];
      const startLeft = componentListRef.current.style.left
        ? Number(componentListRef.current.style.left.slice(0, -2))
        : 0;
      // 鼠标移动事件
      document.onmousemove = function (e2) {
        const nowPositionX = e2.clientX;
        const offestNum = nowPositionX - startPositionX;
        if (nowPositionX + 1 >= document.body.clientWidth)
          return (document.onmousemove = null);

        // 边界不触发组件位移
        if (
          Math.abs(offestNum) > 10 &&
          ((isNowIndex !== 0 && offestNum > 0) ||
            (isNowIndex !== componentList.length - 1 && offestNum < 0))
        ) {
          setJustNowBarWidthAndLeft(offestNum);
          componentListRef.current.style.left = startLeft + offestNum + "px";
        }
        // 边界情况下展示提示小边框
        else {
          if (isNowIndex === 0) {
            setImgPosition(leftImgRef, Math.abs(offestNum));
          }
          if (isNowIndex === componentList.length - 1) {
            setImgPosition(rightImgRef, Math.abs(offestNum));
          }
        }
      };
      // 鼠标抬起事件
      document.onmouseup = function (e3) {
        const [nowPositionX, nowTime] = [e3.clientX, new Date().getTime()];
        const offestTime = nowTime - startTime;
        const offestNum = nowPositionX - startPositionX;
        const speed = Math.abs(offestNum) / offestTime;
        const componentListRefClientWidth =
          componentListRef.current.clientWidth;
        // 滑动的距离超过一半宽度 或者 滑动速度大于一定程度 切换组件位置
        if (
          Math.abs(offestNum) > componentListRefClientWidth / 2 ||
          speed > 1.3
        ) {
          // 往右滑且，当前不是第一个组件，切换组件位置
          if (offestNum > 0 && isNowIndex !== 0) {
            setIsNowIndex(isNowIndex - 1);
            setHistoryIndex([...historyIndex, isNowIndex - 1]);
          }
          // 往左滑且，当前不是最后一个组件，切换组件位置
          if (offestNum < 0 && isNowIndex !== componentList.length - 1) {
            setIsNowIndex(isNowIndex + 1);
            setHistoryIndex([...historyIndex, isNowIndex + 1]);
          }
          // 非上面情况，则将组件位置重置为当前位置
        } else {
          componentListRef.current.style.transition = `all ${transitionTime}s`;
          componentListRef.current.style.left =
            -1 * isNowIndex * componentListRefClientWidth + "px";
        }

        resetBarStyle();

        // 重置组件旁边两个提示图片位置
        if (isNowIndex === 0) {
          resetImgStyle(leftImgRef);
        } else if (isNowIndex === componentList.length - 1) {
          resetImgStyle(rightImgRef);
        }
        clearFunc();
      };
    };
  }, [componentList.length, historyIndex, isNowIndex]);

  // 初始化，得到组件旁边俩边界图片的高，将宽、左右偏移量，按照高的比例来赋值
  const setImgInitializedClientHeightANdClientWidth = useCallback(() => {
    imgInitializedClientHeight = leftImgRef.current.clientHeight;
    imgInitializedClientWidth = 0.22 * imgInitializedClientHeight;
    imgInitializedLeftOrRight = -0.2 * imgInitializedClientHeight;
    rightImgRef.current.style.witdth = leftImgRef.current.style.witdth =
      imgInitializedClientWidth;
  }, []);

  // isNowIndex变动时设置bar的位置
  const setBarWidthAndLeft = useCallback(() => {
    const barRef = tabListAndBarContainerRef.current.childNodes[0];
    barRef.style.transition = `all ${transitionTime}s`;
    barRef.style.width = barInitializedWidth + "px";
    if (isBarNowLeftOrLeft === "left")
      barRef.style.left = getBarLeftOrLeftPosition(isNowIndex);
    else if (isBarNowLeftOrLeft === "right") {
      barRef.style.right = getBarLeftOrLeftPosition(isNowIndex, "right");
    }
    if (!barInitializedLeft)
      barInitializedLeft = getBarLeftOrLeftPosition(isNowIndex);
  }, [isNowIndex]);

  // 初始化，及清除事件
  useEffect(() => {
    setImgInitializedClientHeightANdClientWidth();
    return () => {
      clearFunc();
    };
  }, [setBarWidthAndLeft, setImgInitializedClientHeightANdClientWidth]);

  // 设置外部滚动条与内部滚动条优先级、设置组件滑动事件、设置bar的位置
  useEffect(() => {
    setBarWidthAndLeft();
    setScrollFuncToScrollToTabContainerParent();
    setEventToComponentListRef();
  }, [
    setBarWidthAndLeft,
    setEventToComponentListRef,
    setScrollFuncToScrollToTabContainerParent,
  ]);

  // 当前Index变动时，切换组件和左右两边提示图片的位置
  useEffect(() => {
    setComponentInView();
    setLeftAndRightImgInView();
  }, [setComponentInView, setLeftAndRightImgInView]);

  // tabListItem 相关

  // tabListItem点击时，切换当前index
  const tabListItemClick = useCallback(
    (index) => {
      if (index !== isNowIndex) {
        setIsNowIndex(index);
        setHistoryIndex([...historyIndex, index]);
      }
    },
    [historyIndex, isNowIndex]
  );

  return (
    <div className={style.scrollToTabContainer} ref={scrollToTabContainer}>
      <div className={style.tabListContainer}>
        <div
          className={style.tabListAndBarContainer}
          ref={tabListAndBarContainerRef}
        >
          <div className={style.tabListItemUnderBar} />
          {tabList.map((item, index) => {
            return (
              <span
                key={index}
                onClick={() => tabListItemClick(index)}
                className={[
                  style.tabListItem,
                  index === isNowIndex ? style.boldFrontSize : "",
                ].join(" ")}
              >
                {item}
              </span>
            );
          })}
        </div>
      </div>
      <div className={style.componentListContainer} ref={componentListRef}>
        <div className={style.leftImg} ref={leftImgRef} />
        {componentList.map((Item, index) => {
          return (
            <div
              className={[
                style.componentListItem,
                isScroll ? style.overFlowScroll : "",
              ].join(" ")}
              key={index}
            >
              {historyIndex.includes(index) && <Item />}
            </div>
          );
        })}
        <div className={style.rightImg} ref={rightImgRef} />
      </div>
    </div>
  );
};

export default ScrollToTab;
